import ctypes
import os
import string
import sys
import cv2
import time
import queue
import threading
import numpy as np
from datetime import datetime

from arena_api.buffer import *
from Device_Find import Device_Find  # 搜索设备


def get_free_space(path):
    free_bytes = ctypes.c_ulonglong(0)
    ctypes.windll.kernel32.GetDiskFreeSpaceExW(ctypes.c_wchar_p(path), None, None, ctypes.pointer(free_bytes))
    return free_bytes

# 1、设置节点
def set_nodes(device, pixel_format):
    nodemap = device.nodemap
    nodes = nodemap.get_node(['Width', 'Height', 'PixelFormat',
                              'ExposureAuto',
                              'GainAuto'])
    nodes['Width'].value = nodes['Width'].max
    nodes['Height'].value = nodes['Height'].max
    nodes['PixelFormat'].value = pixel_format
    nodes['ExposureAuto'].value = 'Continuous'
    nodes['GainAuto'].value = 'Continuous'
    # 配置设备节点以最大帧速率并最小化丢失的帧中
    device.nodemap['AcquisitionMode'].value = 'Continuous'  # 确定设备连续发送图像
    nodemap['AcquisitionFrameRateEnable'].value = True  # 每当设备更改时，自动计算最大FPS
    nodemap['AcquisitionFrameRate'].value = nodemap['AcquisitionFrameRate'].max  # 对于当前设备，设置FPS为最大FPS
    nodemap['DeviceStreamChannelPacketSize'].value = nodemap['DeviceStreamChannelPacketSize'].max

    # 设置流
    tl_stream_nodemap = device.tl_stream_nodemap
    tl_stream_nodemap["StreamBufferHandlingMode"].value = "NewestOnly"  # 设置传输流的属性
    tl_stream_nodemap['StreamAutoNegotiatePacketSize'].value = True
    tl_stream_nodemap['StreamPacketResendEnable'].value = True


# 2、开启流
def Image_trans(device, queue):
    start_time = time.time()
    frame_count = 1
    while True:
        with device.start_stream():
            """无限制获取，直到停止线程"""
            buffer = device.get_buffer()  # 获取缓冲区
            item = BufferFactory.copy(buffer)  # 复制缓冲区[并重新排队]，避免缓冲区用完
            read_img = np.array(item.data, dtype=np.uint8)  # 转换数据格式为Uint8
            queue.put(read_img)
            elapsed_time = time.time() - start_time
            fps = round(frame_count / elapsed_time, 2)
            print(f'fps：{fps}')
            frame_count += 1
            device.requeue_buffer(buffer)

            if 0xFF == ord('q'):
                print('stop')
                device.stop_stream()  # 如果停止线程，则停止设备的传输流
                break
    print('quit')


# 3、保存视频图像的线程
def saved_frames_fun(video_thread, output_path, queue_data):
    print('开始保存')
    i = 1
    while True:
        try:
            save_raw = f'{output_path}/{i}.raw'
            frame_data = queue_data.get(timeout=1)
            with open(save_raw, 'wb') as f:
                f.write(frame_data.tobytes())
            print(f'Has saved {save_raw}.')
            i += 1
        except queue.Empty:
            print(f'queue is Empty, join thread to stop!')
            if not video_thread.is_alive():
                print(f'video_thread to stop!')
                break
    print(f'saved_thread to stop!')


if __name__ == '__main__':
    devices = Device_Find().findDivice()
    device = devices[0]
    # 1、设置节点
    set_nodes(device, 'PolarizedAolp_BayerRG12p')
    # 队列
    image_queue = queue.Queue()
    # 2、开启流
    update_thread = threading.Thread(target=Image_trans,
                                     args=(device, image_queue))

    # 检测磁盘
    available_drives = ['%s:' % d for d in reversed(string.ascii_uppercase) if os.path.exists('%s:' % d)]
    dir = ''
    for drive in available_drives:
        sapce = get_free_space(drive).value
        if sapce >= 13510817904:
            now = datetime.now()
            name = now.strftime("%Y-%m-%d %H-%M-%S")
            dir = f'{drive}/{name}'
            if not os.path.exists(dir):
                os.makedirs(dir)
            break
    print(f'save dir: {dir}')

    # 3、保存线程
    if dir != '':
        print('come in')
        save_thread = threading.Thread(target=saved_frames_fun,
                                       args=(update_thread,
                                             dir,
                                             image_queue))
        update_thread.start()
        save_thread.start()

        update_thread.join()
        save_thread.join()
